#include <iostream>
#include <cstring>
using namespace std;

class StringBad
{
private:
    char * str;
    int len;
    static int num_strings;
public:
    StringBad(const char * s);
    StringBad(const StringBad &st);
    StringBad & operator=(const StringBad &st);
    StringBad();
    ~StringBad();
    friend ostream & operator<<(ostream & os, const StringBad & st);
};
int StringBad::num_strings = 0;
//拷贝构造函数
StringBad::StringBad(const StringBad &st)
{
    num_strings ++;
    len = st.len;
    str = new char[len + 1];
    strcpy(str, st.str);
    cout << num_strings << ": \"" << str << "\" object created"<< endl;
}
//赋值运算符，赋值操作并不创建新的对象
StringBad & StringBad::operator=(const StringBad &st)
{
    if(this == &st)  //检查自我复制
        return *this;
    delete [] str;
    len = st.len;
    str = new char[len + 1];
    strcpy(str, st.str);
    return *this;
}
StringBad::StringBad(const char * s)
{
    len = strlen(s);
    str = new char(len + 1);
    strcpy(str, s);

    //str = s;
    //不能这样做，这只是保存了地址，而没有创建字符串副本
    num_strings ++;
    cout << num_strings << ": \"" << str << "\" object created"<< endl;
}
StringBad::StringBad()
{
    len = 4;
    str = new char[4];
    strcpy(str, "C++");
    num_strings++;
    cout << num_strings << ": \"" << str << "\" object created"<< endl;
}
StringBad::~StringBad()
{
    cout << "\"" << str << "\" object deleted, ";
    --num_strings;
    cout << num_strings << " left\n";
    delete [] str;
}
ostream & operator<<(ostream &os, const StringBad &st)
{
    os << st.str;
    return os;
}
void callme1(StringBad &rsb)
{
    cout << "String passed by reference:\n" << rsb << endl;
}
void callme2(StringBad sb)
{
    cout << "String passed by value:\n" << sb << endl;
}
int main()
{
    StringBad s1("Java");
    StringBad s2("Python");
    StringBad sport("socker");
    cout << s1 << endl << s2 << endl << sport << endl;

    callme1(s1);
    cout << "s2 = " << s2 << endl;
    callme2(s2);   //这个地方是值传递的，在下面一行打印的时候，s2已经被析构了
    cout << "s2 = " << s2 << endl;
    StringBad s3 = s2;  //调用拷贝构造函数
    StringBad s4; 
    s4 = s1;  // 调用赋值运算符

    return 0;
}